﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Text.RegularExpressions;
using System.Runtime.Serialization.Formatters.Binary;

namespace BookSplit
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        private TextContext Book { get; set; }

        private void Open(string path)
        {
            var file = new FileInfo(path);
            if (!file.Exists)
                return;

            if (".stxt".Equals(file.Extension, StringComparison.OrdinalIgnoreCase))
            {
                try
                {
                    var bf = new BinaryFormatter();

                    using (var sm = file.Open(FileMode.Open, FileAccess.Read))
                    {
                        var txt = bf.Deserialize(sm);

                        Book = (TextContext)txt;

                        dgvTxt.DataSource = Book.Splits;
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
            else if (".txt".Equals(file.Extension, StringComparison.OrdinalIgnoreCase))
            {
                string txt = string.Empty;
                try
                {
                    using (var sm = new StreamReader(file.FullName, Encoding.Default))
                    {
                        txt = sm.ReadToEnd();
                    }

                    Book = new TextContext();
                    Book.Content = txt;

                    Split(Book.Content);

                    dgvTxt.DataSource = Book.Splits;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);

                    Book = null;
                }

                Split(txt);
            }
            else
            {
                MessageBox.Show("不支持该文件格式:" + file.Extension);
            }
        }

        private void Save(string path)
        {
            var file = new FileInfo(path);

            if (".stxt".Equals(file.Extension, StringComparison.OrdinalIgnoreCase))
            {
                try
                {
                    if (!file.Directory.Exists)
                        file.Directory.Create();

                    var bf = new BinaryFormatter();
                    using (var sm = file.Open(FileMode.OpenOrCreate, FileAccess.Write))
                    {
                        bf.Serialize(sm, Book);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
            else if (".txt".Equals(file.Extension, StringComparison.OrdinalIgnoreCase))
            {
                var sb = new StringBuilder();

                foreach (var item in Book.Splits)
                {
                    sb.AppendFormat("{0}{1}", item.Title, item.Body);
                }

                try
                {
                    if (!file.Directory.Exists)
                        file.Directory.Create();

                    File.WriteAllText(sfd.FileName, sb.ToString(), Encoding.Default);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
            else
            {
                MessageBox.Show("不支持该文件格式:" + file.Extension);
            }
        }

        private void Split(string sm)
        {
            string parten = @"^(.{0,10}[第0-9零一二三四五六七八九十百千万]{3,}章)(.{1,20})$";
            var reg = new Regex(parten, RegexOptions.Multiline);

            var match = reg.Match(sm);

            Book.Splits = new List<TextItem>();

            while (match.Success)
            {
                var old = match;
                match = match.NextMatch();

                var title = sm.Substring(old.Index, old.Length);
                var body = string.Empty;

                var start = old.Index + old.Length + 1;
                if (match.Success)
                {
                    body = sm.Substring(start, match.Index - start);
                }
                else
                {
                    body = sm.Substring(start);
                }

                if (!string.IsNullOrWhiteSpace(body))
                {
                    Book.Splits.Add(new TextItem { Title = title, Body = body });
                }
            }
        }

        private void menuOpen_Click(object sender, EventArgs e)
        {
            if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                Open(ofd.FileName);
            }
        }

        private void menuSaveAs_Click(object sender, EventArgs e)
        {
            if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                Save(sfd.FileName);
            }
        }

        private void menuExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void menuAppendPre_Click(object sender, EventArgs e)
        {
            var rows = dgvTxt.SelectedRows;
            if (rows.Count == 0)
                return;

            var preIndex = rows[0].Index;

            foreach (DataGridViewRow item in rows)
            {
                var bound = item.DataBoundItem as TextItem;
                var index = Book.Splits.FindIndex(p => p == bound);

                if (index > 0)
                {
                    var pre = Book.Splits[index - 1];

                    pre.Body = string.Format("{0}{1}\n{2}", pre.Body, bound.Title, bound.Body);

                    Book.Splits.Remove(bound);

                    if (preIndex > index - 1)
                        preIndex = index - 1;
                }
            }

            dgvTxt.Refresh();
            dgvTxt.ClearSelection();
            dgvTxt.Rows[preIndex].Selected = true;
        }

        private void menuDelete_Click(object sender, EventArgs e)
        {
            var rows = dgvTxt.SelectedRows;
            if (rows.Count == 0)
                return;

            var preIndex = rows[0].Index;

            foreach (DataGridViewRow item in rows)
            {
                var bound = item.DataBoundItem as TextItem;

                Book.Splits.Remove(bound);
            }

            dgvTxt.Refresh();
            dgvTxt.ClearSelection();
        }

        private void menuFile_DropDownOpening(object sender, EventArgs e)
        {
            menuSaveAs.Enabled = Book != null;
        }

        private void menuReSplit_Click(object sender, EventArgs e)
        {
            Split(Book.Content);
        }

        private void dgvTxt_RowDropped(object source, DataGridView.HitTestInfo traget)
        {
            var items = dgvTxt.SelectedRows
                .Cast<DataGridViewRow>()
                .OrderBy(p => p.Index)
                .Select(p => p.DataBoundItem as TextItem)
                .ToArray();

            if (items.Length > 0)
            {
                foreach (var item in items)
                {
                    Book.Splits.Remove(item);
                }

                var index = traget.RowIndex - items.Length;
                if (index < 0)
                    index = 0;

                Book.Splits.InsertRange(index, items);

                dgvTxt.ClearSelection();

                foreach (var item in items)
                {
                    var i = Book.Splits.FindIndex(p => p == item);
                    if (i >= 0)
                        dgvTxt.Rows[i].Selected = true;
                }
            }
        }

        private void menuEdit_DropDownOpening(object sender, EventArgs e)
        {
            menuReSplit.Enabled = Book != null && Book.Content != null;
        }

        private void dgvTxt_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {
            e.Cancel = true;
            dgvTxt.DataSource = this.Book.Splits;
        }
    }
}
